﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace RFIDSystem.Common.Helper
{
    /// <summary>
    /// REW系列 2.4G 读写器通讯协议 SDK
    /// </summary>
    public class REWReader : IDisposable
    {
        private SerialPort _serialPort;
        private TcpClient _tcpClient;
        private NetworkStream _netStream;

        private readonly bool _useSerial;

        #region ==== 初始化 ====
        //public REWReader(string portName, int baudRate = 115200)
        //{
        //    _useSerial = true;
        //    _serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
        //    _serialPort.ReadTimeout = 2000;
        //    _serialPort.WriteTimeout = 2000;
        //}

        public REWReader(string ip, int port = 20058)
        {
            _useSerial = false;
            _tcpClient = new TcpClient();
            _tcpClient.Connect(ip, port);
            _netStream = _tcpClient.GetStream();
        }
        public TagInfo GetOneTag()
        {
            var resp = SendAndReceive(0x2F, new byte[] { 0x01 }); // 获取缓存一条记录
            return TagInfo.Parse(resp);
        }

        public TagInfo[] GetAllTags()
        {
            var resp = SendAndReceive(0x2F, new byte[] { 0x02 }); // 获取所有记录
                                                                  // 假设多条标签拼接，需要逐条解析
            var tags = new System.Collections.Generic.List<TagInfo>();

            int index = 0;
            while (index < resp.Length)
            {
                int len = resp[index]; // 假设每条前有长度
                if (len <= 0 || index + len > resp.Length) break;

                byte[] oneTag = new byte[len];
                Array.Copy(resp, index, oneTag, 0, len);
                tags.Add(TagInfo.Parse(oneTag));
                index += len;
            }
            return tags.ToArray();
        }
        public void Open()
        {
            if (_useSerial && !_serialPort.IsOpen)
                _serialPort.Open();
        }

        public void Close()
        {
            if (_useSerial && _serialPort.IsOpen)
                _serialPort.Close();
            else if (!_useSerial && _tcpClient.Connected)
                _tcpClient.Close();
        }

        public void Dispose()
        {
            Close();
            _serialPort?.Dispose();
            _netStream?.Dispose();
            _tcpClient?.Dispose();
        }
        #endregion

        #region ==== 协议通用 ====
        private byte[] BuildPacket(byte cmd, byte[] data = null, byte deviceAddr = 0x00)
        {
            int dataLen = data?.Length ?? 0;
            byte lenLow = (byte)(dataLen & 0xFF);
            byte lenHigh = (byte)((dataLen >> 8) & 0xFF);

            byte[] buffer = new byte[7 + dataLen];
            buffer[0] = 0x1B; // Header
            buffer[1] = cmd;
            buffer[2] = 0x00; // Sequence
            buffer[3] = deviceAddr;
            buffer[4] = lenLow;
            buffer[5] = lenHigh;

            if (dataLen > 0)
                Array.Copy(data, 0, buffer, 6, dataLen);

            buffer[buffer.Length - 1] = CalcBCC(buffer, buffer.Length - 1);
            return buffer;
        }

        private byte CalcBCC(byte[] data, int size)
        {
            byte bcc = 0;
            for (int i = 0; i < size; i++)
                bcc ^= data[i];
            return bcc;
        }

        private byte[] SendAndReceive(byte cmd, byte[] data = null)
        {
            var packet = BuildPacket(cmd, data);
            if (_useSerial) _serialPort.Write(packet, 0, packet.Length);
            else _netStream.Write(packet, 0, packet.Length);

            // 读取返回头
            byte[] header = new byte[6];
            ReadBytes(header, 0, 6);
            int dataLen = header[4] + (header[5] << 8);

            byte[] resp = new byte[dataLen + 1];
            ReadBytes(resp, 0, resp.Length);
            return resp;
        }

        private void ReadBytes(byte[] buffer, int offset, int count)
        {
            if (_useSerial)
            {
                int read = 0;
                while (read < count)
                    read += _serialPort.Read(buffer, offset + read, count - read);
            }
            else
            {
                int read = 0;
                while (read < count)
                    read += _netStream.Read(buffer, offset + read, count - read);
            }
        }
        #endregion

        #region ==== 系统指令 (0x01~0x22) ====
        public bool FreeReader() => SendAndReceive(0x01)[0] == 0x00;

        public string GetDeviceVersion()
        {
            var resp = SendAndReceive(0x02);
            return Encoding.ASCII.GetString(resp, 0, resp.Length - 1);
        }

        public byte[] GetDeviceId() => SendAndReceive(0x03);

        public bool SetDeviceId(byte[] id16)
        {
            if (id16.Length != 16) throw new ArgumentException("必须16字节");
            return SendAndReceive(0x04, id16)[0] == 0x00;
        }

        public DateTime GetDeviceTime()
        {
            var resp = SendAndReceive(0x05);
            return new DateTime(2000 + resp[0], resp[1], resp[2], resp[3], resp[4], resp[5]);
        }

        public bool SetDeviceTime(DateTime dt)
        {
            byte[] data = new byte[7] {
                (byte)(dt.Year - 2000),
                (byte)dt.Month, (byte)dt.Day,
                (byte)dt.Hour, (byte)dt.Minute, (byte)dt.Second,
                (byte)dt.DayOfWeek
            };
            return SendAndReceive(0x06, data)[0] == 0x00;
        }

        public bool SetDO1(bool on, byte delay = 0x00)
        {
            byte[] data = { (byte)(on ? 1 : 0), delay, 0x01 };
            return SendAndReceive(0x07, data)[0] == 0x00;
        }

        public bool SetDO2(bool on, byte delay = 0x00)
        {
            byte[] data = { (byte)(on ? 1 : 0), delay, 0x01 };
            return SendAndReceive(0x08, data)[0] == 0x00;
        }

        public bool ResetDevice() => SendAndReceive(0x0D)[0] == 0x00;

        public bool Beep(byte duration, byte pause, byte repeat)
        {
            byte[] data = { duration, pause, repeat };
            return SendAndReceive(0x0F, data)[0] == 0x00;
        }
        #endregion

        #region ==== RF操作指令 (0x25~0x32) ====
        public bool SetRfParams(byte[] antParams16) => SendAndReceive(0x25, antParams16)[0] == 0x00;

        public byte[] GetRfParams() => SendAndReceive(0x26);

        public bool StartInventory(ushort seconds = 0xFFFF)
        {
            byte[] data = BitConverter.GetBytes(seconds);
            return SendAndReceive(0x27, data)[0] == 0x00;
        }

        public bool StopInventory() => SendAndReceive(0x28)[0] == 0x00;
        #endregion

        #region ==== 缓存操作指令 (0x2F, 0xF5~0xFA) ====
        public byte[] GetRecords() => SendAndReceive(0x2F, new byte[] { 0x02 });

        public byte[] GetVipList16() => SendAndReceive(0xF5);

        public bool SetVipList16(byte[] vipData512) => SendAndReceive(0xF6, vipData512)[0] == 0x00;

        public byte[] GetVipList4() => SendAndReceive(0xF9);

        public bool SetVipList4(byte[] vipData512) => SendAndReceive(0xFA, vipData512)[0] == 0x00;
        #endregion
        /// <summary>
        /// 设备用户参数 (64字节)
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct DeviceUserParameter
        {
            public byte U00_ValidDO1Time;
            public byte U01_ValidDO2Time;
            public byte U02_InvalidDO1Time;
            public byte U03_InvalidDO2Time;
            public byte U04_RecordInterval0;
            public byte U05_RecordInterval1;
            public byte U06_ReadTagInterval;
            public byte U07_TagDataType;
            public byte U08_DeviceWorkMode;
            public byte U09_SaveDataFlag;
            public byte U10_DataOutPort;
            public byte U11_BeepEnable;
            public byte U12_TagDataCtlEnable;
            public byte U13_TagCtlStWord1;
            public byte U14_TagCtlWordData1;
            public byte U15_TagCtlStWord2;
            public byte U16_TagCtlWordData2;
            public byte U17_TagCtlNo;
            public byte U18_TagCtlWorkTimer;
            public byte U19_WgType;
            public byte U20_WgByteStartPos;
            public byte U21_WgBitStartPos;
            public byte U22_WgPulseCycle;
            public byte U23_DataPacketFormat;
            public byte U24_RS485BaudRate;
            public byte U25_UsbDataAddress;
            public byte U26_UsbDataLength;
            public byte U27_UsbDataFormat;
            public byte U28_DeviceWT1;
            public byte U29_DeviceWT2;
            public byte U30_DataFormatTimeEn;
            public byte U31_TriggerWorkDelay;
            public byte U32_DeviceAddr;
            public byte U33_DeviceGroupNo;
            public byte U34_AlivePackage;
            public byte U35_DisabledAntPackage;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] U36_AccessPwd;
            public byte U40_ModbusAutoOutEn;
            public byte U41_ModbusWordStartAddr;
            public byte U42_ModbusWordLen;
            public byte U43_ModbusRwSuccessCountUpEn;
            public byte U44_Reversed;
            public byte U45_DINStatusDataEn;
            public byte U46_CustomOutHead01En;
            public byte U47_CustomOutHead01Data;
            public byte U48_CustomOutHead02En;
            public byte U49_CustomOutHead02Data;
            public byte U50_CustomOutTagDataStartAddr;
            public byte U51_CustomOutTagDataLen;
            public byte U52_CustomOutEnd01En;
            public byte U53_CustomOutEnd01Data;
            public byte U54_CustomOutEnd02En;
            public byte U55_CustomOutEnd02Data;
            public byte U56_CustomOutInterval;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
            public byte[] U57_Reversed;
        }

        /// <summary>
        /// 网络参数 (128字节)
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        public struct ReaderNetWorkParameter
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] IPAddress;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] NetMask;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            public byte[] GateWay;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
            public string WiFiSta_SSID;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
            public string WiFiSta_Encrypt;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
            public string WiFiSta_Pwd;

            public byte Eth_link_mode;
            public byte Eth_work_mode;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
            public string Server_address;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
            public string TcpIpPort;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
            public byte[] Reversed;
        }

        /// <summary>
        /// RF天线参数 (16字节)
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct ReaderUserAntParameter
        {
            public byte Ant01Enabled;
            public byte Ant01AirRate;
            public byte Ant01ChannelNumber;
            public byte Ant01Power;
            public byte Ant01Attenuator;

            public byte Ant02Enabled;
            public byte Ant02AirRate;
            public byte Ant02ChannelNumber;
            public byte Ant02Power;
            public byte Ant02Attenuator;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
            public byte[] Reserved;

            public byte Ant03Enabled;
            public byte Ant03AirRate;
            public byte Ant03ChannelNumber;
            public byte Ant03Power;
            public byte Ant03Attenuator;
        }

        /// <summary>
        /// struct 和 byte[] 互转工具
        /// </summary>
        public static class StructConverter
        {
            public static byte[] ToBytes<T>(T str) where T : struct
            {
                int size = Marshal.SizeOf(typeof(T));
                byte[] arr = new byte[size];
                IntPtr ptr = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(str, ptr, true);
                Marshal.Copy(ptr, arr, 0, size);
                Marshal.FreeHGlobal(ptr);
                return arr;
            }

            public static T FromBytes<T>(byte[] arr) where T : struct
            {
                T str = new T();
                int size = Marshal.SizeOf(typeof(T));
                if (arr.Length < size) throw new ArgumentException("字节数组长度不足");
                IntPtr ptr = Marshal.AllocHGlobal(size);
                Marshal.Copy(arr, 0, ptr, size);
                str = Marshal.PtrToStructure<T>(ptr);
                Marshal.FreeHGlobal(ptr);
                return str;
            }
        }
    }
}
